package dai.samples.elasticsearch.service.impl;

import dai.samples.elasticsearch.entity.User;
import dai.samples.elasticsearch.repository.UserRepository;
import dai.samples.elasticsearch.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author daify
 * @date 2019-07-17 16:08
 **/
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired 
    UserRepository userRepository;
    
    @Autowired
    private ElasticsearchTemplate template;

    /**
     * spring根据规则生成的查询
     * @param score1
     * @param score2
     */
    @Override
    public List<User> findAllByScoreBetween(Integer score1, Integer score2) {
        return userRepository.findAllByScoreBetween(score1, score2);
    }

    /**
     * 创建索引
     * @param clazz
     */
    @Override
    public void createIndex(Class clazz) {
        // 创建索引，会根据Item类的@Document注解信息来创建
        template.createIndex(clazz);
    }

    /**
     * 删除索引
     * @param clazz
     */
    @Override
    public void deleteIndex(Class clazz) {
        // 创建索引，会根据Item类的@Document注解信息来创建
        template.deleteIndex(clazz);
    }

    /**
     * 验证索引是否存在
     * @param clazz
     * @return
     */
    @Override
    public Boolean indexExists(Class clazz) {
        return template.indexExists(clazz);
    }


    /**
     * 保存/更新数据
     * @param user
     * @return
     */
    @Override 
    public Long saveUser(User user) {
        User result = userRepository.save(user);
        return result.getId();
    }

    @Override
    public void saveAllUser(List<User> userList) {
        userRepository.saveAll(userList);
    }

    /**
     * 查询数据
     * @param sortName
     * @return
     */
    @Override
    public List<User> findAll(String sortName) {
        Iterable <User> all = userRepository.findAll(Sort.by(sortName).ascending());
        List<User> rest = new ArrayList <>();
        all.forEach(item -> rest.add(item));
        return rest;
        
    }

    /**
     * 条件查询
     * @param key
     * @param value
     * @return
     */
    @Override
    public Page<User> myQuery(String key,String value) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.matchQuery(key, value));
        Page<User> items = userRepository.search(queryBuilder.build());
        return items;
    }

    /**
     * 条件查询
     * @param key
     * @param value
     * @return
     */
    @Override
    public Page<User> myLikeQuery(String key, String value) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 模糊查询
        queryBuilder.withQuery(QueryBuilders.fuzzyQuery(key, value));
        Page<User> items = userRepository.search(queryBuilder.build());
        return items;
    }

    /**
     * 分页查询
     * @param key
     * @param value
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Page<User> myPageQuery(String key,String value,Integer page,Integer pageSize) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.termQuery(key, value));
        queryBuilder.withPageable(PageRequest.of(page,pageSize));

        // 搜索，获取结果
        Page<User> items = userRepository.search(queryBuilder.build());
        return items;
    }

    /**
     * 排序查询
     * @param key
     * @param value
     * @param sortField
     * @param order
     * @return
     */
    @Override
    public Page<User> myQuerySort(String key, String value, String sortField, SortOrder order) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 添加基本分词查询
        queryBuilder.withQuery(QueryBuilders.matchQuery(key, value));
        queryBuilder.withSort(SortBuilders.fieldSort(sortField).order(order));
        Page<User> items = userRepository.search(queryBuilder.build());
        return items;
    }

    /**
     * 聚合
     */
    @Override
    public List<StringTerms.Bucket> aggStringTerms(String termsName,String field) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合，聚合类型为terms，聚合名称为brands，聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms(termsName).field(field + ".keyword"));
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<User> aggPage = (AggregatedPage<User>) userRepository.search(queryBuilder.build());
        // 3.1、从结果中取出名为brands的那个聚合，
        // 因为是利用String类型字段来进行的term聚合，所以结果要强转为StringTerm类型
        StringTerms agg = (StringTerms) aggPage.getAggregation(termsName);
        // 3.2、获取桶
        List<StringTerms.Bucket> buckets = agg.getBuckets();
        return buckets;
    }

    /**
     * 嵌套聚合
     */
    @Override
    public List<StringTerms.Bucket> subAggStringTermsSum(String termsName,String termsNameAvg,String field,String fieldSum) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 不查询任何结果
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
        // 1、添加一个新的聚合，聚合类型为terms，聚合名称为brands，聚合字段为brand
        queryBuilder.addAggregation(
                AggregationBuilders.terms(termsName).field(field + ".keyword")
                .subAggregation(AggregationBuilders.sum(termsNameAvg).field(fieldSum)));
        // 2、查询,需要把结果强转为AggregatedPage类型
        AggregatedPage<User> aggPage = (AggregatedPage<User>) userRepository.search(queryBuilder.build());
        // 3.1、从结果中取出名为brands的那个聚合，
        // 因为是利用String类型字段来进行的term聚合，所以结果要强转为StringTerm类型
        StringTerms agg = (StringTerms) aggPage.getAggregation(termsName);
        // 3.2、获取桶
        List<StringTerms.Bucket> buckets = agg.getBuckets();
        return buckets;

    }


}

